package com.qidi.mvcframework.servlet.webmvc.servlet;

import com.qidi.mvcframework.servlet.annotation.MyRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class MyHandlerAdapter {
    public MyModelAndView handler(HttpServletRequest req, HttpServletResponse resp, MyHandlerMapping handler) throws Exception {
        // ########################### 处理参数 ###########################

        // --------------------------- 有 Spring 注解的参数 ---------------------------
        // 保存 参数名称 和 参数位置
        Map<String, Integer> paramIndexMapping = new HashMap<>();

        Method method = handler.getMethod();
        // 下面的这种方法是拿不到 @MyRequestParam("xx") 的，因为这个 parameterType 是 方法 的参数类型
//                MyRequestParam requestParam = parameterType.getAnnotation(MyRequestParam.class);
//                String paramName = requestParam.value();
        // 拿到方法参数上的注解类型
        Annotation[][] annotations = method.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            for (Annotation annotation : annotations[i]) {
                if (annotation instanceof MyRequestParam) {
                    String paramName = ((MyRequestParam) annotation).value();
                    if ("".equals(paramName.trim())) continue;
                    paramIndexMapping.put(paramName, i);
                }
            }
        }

        // --------------------------- 补充 req 和 resp ---------------------------
        // 形参类型
        Class<?>[] parameterTypes = method.getParameterTypes();

        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> parameterType = parameterTypes[i];
            if (parameterType == HttpServletRequest.class || parameterType == HttpServletResponse.class) {
                // 没有注解，直接使用参数的全类名 不可能有参数类型和顺序完全相同的同名方法
                paramIndexMapping.put(parameterType.getName(), i);
            }
        }

        // --------------------------- 拼接实参列表 ---------------------------
        Map<String, String[]> parameterMap = req.getParameterMap();

        // 实参列表
        Object[] params = new Object[parameterTypes.length];

        for (Map.Entry<String, String[]> param : parameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue())
                    // 去掉 [ ]
                    .replaceAll("\\[|\\]", "")
                    // 去掉 空格
                    .replaceAll("\\s", ",");

            if (!paramIndexMapping.containsKey(param.getKey())) continue;

            Integer index = paramIndexMapping.get(param.getKey());

            // Spring 允许自定义类型转换器 Converter，这里先不支持
            params[index] = castStringValue(value, parameterTypes[index]);
        }

        if (paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {
            Integer index = paramIndexMapping.get(HttpServletRequest.class.getName());
            params[index] = req;
        }
        if (paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {
            Integer index = paramIndexMapping.get(HttpServletResponse.class.getName());
            params[index] = resp;
        }

        // --------------------------- 封装结果为 ModelAndView ---------------------------
        Object result = method.invoke(handler.getController(), params);
        if (result == null || result instanceof Void) return null;

        // 忽略在方法上存在注解 @ResponseBody 的情况，统一返回 ModelAndView
        boolean isModelAndView = method.getReturnType() == MyModelAndView.class;
        if (isModelAndView){
            return (MyModelAndView) result;
        }

        return null;
    }

    private Object castStringValue(String value, Class<?> parameterType) {
        if (String.class == parameterType) {
            return value;
        } else if (Integer.class == parameterType) {
            return Integer.valueOf(value);
        } else if (Double.class == parameterType) {
            return Double.valueOf(value);
        } else {
            // 其他类型的 略
            if (value != null) return value;
        }
        return null;
    }
}
